分组 Group
Group 是一个有标题栏的带边框盒子。如果说 Panel 是隐形的 <div>,那 Group 就是醒目的 <fieldset>——它天生带有视觉分组能力,能让用户一眼看出"这一块内容是相关的"。
一句话理解
Group = Panel + 标题栏 + 边框。适合把相关的控件打包成一个视觉单元。
函数原型
bool BeginGroup(const HXString &Title, GroupProfile &Profile);
void EndGroup(GroupProfile &Profile);
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
Title | const HXString & | 显示在分组顶部的标题文字。使用 HXStr("标题") 或 L"标题"。 |
Profile | GroupProfile & | 分组的配置结构体。必须是 static 或全局变量。 |
返回值
| 类型 | 说明 |
|---|---|
bool | true —— 分组可见且未折叠,继续往里面放控件。false —— 分组被折叠或不可见,跳过内部绘制。 |
GroupProfile 结构体
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Size | HXPoint | {-1, -1} | 分组尺寸。{-1, -1} 表示自动根据内容计算。 |
Padding | HXGInt | 8 | 内边距:边框到内部控件的距离。 |
Margin | HXGInt | 5 | 外边距:分组与外部其他控件的距离。 |
Direction | HXLayoutDirection | Vertical | 内部布局方向。 |
ItemAlign | HXLayoutAlign | Stretch | 子控件的对齐方式。 |
ClipContent | bool | false | 是否裁剪超出边界的内容。 |
TitleBarHeight | int | 24 | 标题栏高度(像素)。 |
FontSize | int | 20 | 标题文字字体大小。 |
注意背景色和边框色
Group 的边框和标题栏颜色来自当前主题的 GroupBorderColor 和 GroupTitleBackground,而不是像 Panel 那样由 Profile 直接指定。如果你需要自定义颜色,建议改用 Panel 手动实现。
基本用法
最简单的 Group,就是把一堆相关的控件包起来:
static HX::GroupProfile gp;
if (HX::BeginGroup(HXStr("音频设置"), gp)) {
HX::Slider1f(HXStr("主音量"), masterVol, sp);
HX::Slider1f(HXStr("背景音乐"), bgmVol, sp);
HX::Slider1f(HXStr("音效"), sfxVol, sp);
HX::EndGroup(gp);
}
与 Panel 的区别
| 特性 | Panel | Group |
|---|---|---|
| 标题栏 | ❌ 无 | ✅ 有 |
| 边框样式 | 手动设置 BorderColor | 自动使用主题样式 |
| 背景色 | 手动设置 BackgroundColor | 自动使用主题样式 |
| 用途 | 自由容器、卡片、布局隔离 | 功能分组、设置项归类 |
| 视觉权重 | 轻 | 重(自带标题,更醒目) |
怎么选?
- 要做左侧导航栏、内容卡片、透明布局隔离 → Panel
- 要做"音频设置"、"网络配置"、"外观选项"这种带标题的分组 → Group
嵌套使用
Group 可以嵌套 Group,Panel 和 Group 也可以互相嵌套。不过注意:嵌套太深会让 UI 显得臃肿,一般两到三层就够了。
static HX::GroupProfile outer;
static HX::GroupProfile inner;
if (HX::BeginGroup(HXStr("游戏设置"), outer)) {
HX::Text(HXStr("基础选项..."));
if (HX::BeginGroup(HXStr("画面"), inner)) {
HX::Slider1f(HXStr("分辨率缩放"), scale, sp);
HX::Checkbox(HXStr("全屏"), cp);
HX::EndGroup(inner);
}
if (HX::BeginGroup(HXStr("操控"), inner)) {
HX::Slider1f(HXStr("鼠标灵敏度"), sens, sp);
HX::Checkbox(HXStr("反转 Y 轴"), cp);
HX::EndGroup(inner);
}
HX::EndGroup(outer);
}
完整示例代码
#include <include/hex.h>
#include <include/impl/EasyX/hex_impl_easyx.h>
int main() {
initgraph(800, 600);
setbkcolor(WHITE);
cleardevice();
HX::HXInitForEasyX();
HX::SetBuffer(GetWorkingImage());
BeginBatchDraw();
static HX::WindowProfile wp;
wp.Size = {500, 500};
static float masterVol = 0.8f, bgmVol = 0.6f, sfxVol = 0.9f;
static HX::SliderProfile1f sp;
static HX::CheckboxProfile cp;
while (true) {
HX::HXBegin();
ExMessage msg;
while (peekmessage(&msg)) {
HX::PushMessage(HX::GetHXMessage(&msg));
}
HX::Window(HXStr("Group 演示"), wp);
// ---------- 音频设置组 ----------
static HX::GroupProfile audioGp;
if (HX::BeginGroup(HXStr("音频设置"), audioGp)) {
HX::Slider1f(HXStr("主音量"), masterVol, sp);
HX::Slider1f(HXStr("背景音乐"), bgmVol, sp);
HX::Slider1f(HXStr("音效"), sfxVol, sp);
HX::EndGroup(audioGp);
}
// ---------- 显示设置组 ----------
static HX::GroupProfile displayGp;
if (HX::BeginGroup(HXStr("显示设置"), displayGp)) {
HX::Checkbox(HXStr("全屏模式"), cp);
HX::Checkbox(HXStr("垂直同步"), cp);
HX::Checkbox(HXStr("显示 FPS"), cp);
HX::EndGroup(displayGp);
}
// ---------- 嵌套组 ----------
static HX::GroupProfile advancedGp;
if (HX::BeginGroup(HXStr("高级选项"), advancedGp)) {
HX::Text(HXStr("以下选项修改后需要重启游戏:"));
static HX::GroupProfile netGp;
if (HX::BeginGroup(HXStr("网络"), netGp)) {
HX::Checkbox(HXStr("使用 IPv6"), cp);
HX::Checkbox(HXStr("代理服务器"), cp);
HX::EndGroup(netGp);
}
HX::EndGroup(advancedGp);
}
HX::End();
HX::Render();
FlushBatchDraw();
Sleep(16);
}
closegraph();
return 0;
}
小建议
Group 的标题是用户快速扫描界面时的"路标"。起个好标题(如"音频设置"而不是"设置1")能显著提升界面的可读性。